﻿/*
 * Name:        UserInterface class
 * Description: Handles user interface inputs and drawing
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

using Gyvate.Worldspawn;
using Gyvate.Util;

namespace Gyvate.GFX
{
    internal class UserInterface
    {
        private Game m_game;
        private LinkedList<SnkPanel> m_children;

        private bool m_bIsMenuOpen = false;

        private bool m_bMouseHeld = false;
        private Vector2d m_vecLastMouse = new Vector2d(0, 0);
        private Vector2d m_vecInput = new Vector2d(0, 0);

        /*UI Elements*/

        /*Panels*/
        SnkPanel m_mainPanel;
        SnkPanel m_pausePanel;

        /*Labels*/
        SnkLabel m_leftPanel;
        SnkLabel m_rightPanel;
        SnkLabel m_endLabel;

        /*Image panel*/
        /*Debug*/
        SnkImgPanel[] m_dbgTiles;

        /*Buttons*/
        SnkButton m_buttonQuit;
        SnkButton m_buttonRestart;
        /*Debug*/
        SnkButton m_dbgButtonQuitAndSave;


        public UserInterface(Game game)
        {
            m_game = game;
            m_children = new LinkedList<SnkPanel>();

            CreateInterface();
        }

        public void Draw()
        {
            for (LinkedListNode<SnkPanel> it = m_children.First; it != null; it = it.Next)
                it.Value.Draw();
        }

        private void CreateInterface()
        {
            CreateBottomInterface();
            CreatePausemenu();
            CreateEndMenu();
        }

        private void CreateBottomInterface()
        {
            /*
             * Create the main panel in which UI is stored
             */
            Vector2d vecSpriteSize = new Vector2d(Constants.SPRITE_SIZE, Constants.SPRITE_SIZE);    //Reusable

            Vector2d posMainPanel = new Vector2d(0, (Constants.FIELD_HEIGHT + 1) * Constants.SPRITE_SIZE);
            Vector2d sizeMainPanel = new Vector2d((Constants.FIELD_WIDTH + 1) * Constants.SPRITE_SIZE,
                (Constants.UI_HEIGHT - Constants.FIELD_HEIGHT + 1) * Constants.SPRITE_SIZE);

            m_mainPanel = new SnkPanel(m_game, new Dimensions2d(posMainPanel, sizeMainPanel));

            m_children.AddLast(m_mainPanel);

            /*
             * Create different UI layout when in map maker
             */
            if (!m_game.IsDebug())
            {
                /*
                 * Create both score panels
                 */
                Vector2d scoreMainPos = vecSpriteSize + posMainPanel;
                Vector2d scoreMainSize = (sizeMainPanel / 2);
                scoreMainSize.x -= (int)(Constants.SPRITE_SIZE / 2);

                m_leftPanel = new SnkLabel(m_game, new Dimensions2d(scoreMainPos, scoreMainSize));
                m_leftPanel.SetBGColour(Color.DarkCyan);

                m_children.AddLast(m_leftPanel);

                /*
                 * Create speed panel
                 */
                Vector2d speedMainPos = new Vector2d(scoreMainPos);
                speedMainPos.x += scoreMainSize.x + (int)(Constants.SPRITE_SIZE);
                Vector2d speedMainSize = new Vector2d(scoreMainSize);
                speedMainSize.x -= (int)(Constants.SPRITE_SIZE * 2);

                m_rightPanel = new SnkLabel(m_game, new Dimensions2d(speedMainPos, speedMainSize), "");
                m_rightPanel.SetBGColour(Color.DarkCyan);

                m_children.AddLast(m_rightPanel);
            }
            else
            {
                Vector2d[] posTile = new Vector2d[Constants.UI_MM_NUM_ITEMS];
                Vector2d[] sizeTile = new Vector2d[Constants.UI_MM_NUM_ITEMS];

                m_dbgTiles = new SnkImgPanel[Constants.UI_MM_NUM_ITEMS];

                /* Begin WALL */
                posTile[0] = new Vector2d(vecSpriteSize + posMainPanel);
                sizeTile[0] = (sizeMainPanel / 2);
                sizeTile[0].x /= Constants.UI_MM_NUM_ITEMS;

                m_dbgTiles[0] = new SnkImgPanel(m_game, new Dimensions2d(posTile[0], sizeTile[0]));
                m_dbgTiles[0].SetImage(Constants.SPRITE_WALL);
                m_dbgTiles[0].SetCommand("build " + (int)TileList.TILE_WALL);
                m_children.AddLast(m_dbgTiles[0]);
                /* End wall */

                /* Begin Spawn 0deg */
                posTile[1] = new Vector2d(posTile[0]);
                sizeTile[1] = new Vector2d(sizeTile[0]);
                posTile[1].x += sizeTile[1].x;

                m_dbgTiles[1] = new SnkImgPanel(m_game, new Dimensions2d(posTile[1], sizeTile[1]));
                m_dbgTiles[1].SetImage(Constants.SPRITE_SPAWN);
                m_dbgTiles[1].SetCommand("build " + (int)TileList.TILE_SNAKESPAWN);
                m_children.AddLast(m_dbgTiles[1]);
                /* End wall */

                /* Begin Spawn 90deg */
                posTile[2] = new Vector2d(posTile[1]);
                sizeTile[2] = new Vector2d(sizeTile[1]);
                posTile[2].x += sizeTile[2].x;

                m_dbgTiles[2] = new SnkImgPanel(m_game, new Dimensions2d(posTile[2], sizeTile[2]));
                m_dbgTiles[2].SetImage(Constants.SPRITE_SPAWN_90);
                m_dbgTiles[2].SetCommand("build " + (int)TileList.TILE_SNAKESPAWN_90);
                m_children.AddLast(m_dbgTiles[2]);
                /* End wall */

                /* Begin Spawn 180deg */
                posTile[3] = new Vector2d(posTile[2]);
                sizeTile[3] = new Vector2d(sizeTile[2]);
                posTile[3].x += sizeTile[3].x;

                m_dbgTiles[3] = new SnkImgPanel(m_game, new Dimensions2d(posTile[3], sizeTile[3]));
                m_dbgTiles[3].SetImage(Constants.SPRITE_SPAWN_180);
                m_dbgTiles[3].SetCommand("build " + (int)TileList.TILE_SNAKESPAWN_180);
                m_children.AddLast(m_dbgTiles[3]);
                /* End wall */


                /* Begin Spawn 270deg */
                posTile[4] = new Vector2d(posTile[3]);
                sizeTile[4] = new Vector2d(sizeTile[3]);
                posTile[4].x += sizeTile[4].x;

                m_dbgTiles[4] = new SnkImgPanel(m_game, new Dimensions2d(posTile[4], sizeTile[4]));
                m_dbgTiles[4].SetImage(Constants.SPRITE_SPAWN_270);
                m_dbgTiles[4].SetCommand("build " + (int)TileList.TILE_SNAKESPAWN_270);
                m_children.AddLast(m_dbgTiles[4]);
                /* End wall */
            }
        }

        public void UpdateUI()
        {
            if (m_game.IsDebug())
            {
            }
            else
            {
                string leftText = "";
                leftText += "Taškai: " + m_game.GetGameRules().GetScore() + "\n";
                leftText += "Suvalgyta: " + m_game.GetGameRules().GetEaten() + "\n";
                m_leftPanel.SetText(leftText);

                string rightText = "";
                rightText += "Dabartinis greitis: " + m_game.GetGameRules().GetSpeed() + "\n";
                rightText += "Apšvietimos skersmuo: " + m_game.GetGameRules().GetSpotLightSize() + "\n";
                /*
                rightText += "-------------DEBUG--------------\n";
                rightText += "Gyvatė: x" + m_game.GetSnake().GetHead().GetPos().x + " y" + m_game.GetSnake().GetHead().GetPos().y + "\n";*/
                m_rightPanel.SetText(rightText);
            }
        }

        public void SendMouseInput(MouseEventArgs e)
        {
            bool commandRan = false;

            if (e.Button == MouseButtons.Left)
            {
                // Send  input to buttons
                for (LinkedListNode<SnkPanel> it = m_children.First; it != null; it = it.Next)
                    if (it.Value is SnkImgPanel || it.Value is SnkButton)
                    {
                        Dimensions2d dim = it.Value.GetDimensions();

                        if (dim.pos.x > e.X || dim.pos.y > e.Y)
                            continue;

                        if (dim.pos.x + dim.size.x < e.X || dim.pos.y + dim.size.y < e.Y)
                            continue;

                        if (!it.Value.IsVisible())
                            continue;

                        ((SnkButton)it.Value).OnClick();
                        commandRan = true;
                        break;
                    }
            }

            if (commandRan)
                return;

            SendMouseInputContinuous(e);
        }

        public void SendMouseInputContinuous(MouseEventArgs e)
        {
            if (m_bIsMenuOpen)
                return;

            if (!m_game.IsDebug())
            {
                bool wasSet = false;

                if (!m_bMouseHeld && e.Button == MouseButtons.Left)
                {
                    m_vecLastMouse = new Vector2d(e.X, e.Y);
                    m_bMouseHeld = true;
                }
                else if (m_bMouseHeld && e.Button != MouseButtons.Left)
                {
                    m_bMouseHeld = false;

                    m_vecInput = m_vecLastMouse - (new Vector2d(e.X, e.Y));
                    m_vecInput.Normalize();
                    wasSet = true;
                }

                if (m_game.IsMouseReset() && !wasSet)
                    return;

                if (m_vecInput.x == 1)
                {
                    m_game.SendInput(Keys.Right, true, true);
                    m_game.SendInput(Keys.Left, false, true);
                }
                else if (m_vecInput.x == -1)
                {
                    m_game.SendInput(Keys.Right, false, true);
                    m_game.SendInput(Keys.Left, true, true);
                }
                else
                {
                    m_game.SendInput(Keys.Right, true, true);
                    m_game.SendInput(Keys.Left, true, true);
                }

                if (m_vecInput.y == 1)
                {
                    m_game.SendInput(Keys.Up, false, true);
                    m_game.SendInput(Keys.Down, true, true);
                }
                else if (m_vecInput.y == -1)
                {
                    m_game.SendInput(Keys.Up, true, true);
                    m_game.SendInput(Keys.Down, false, true);
                }
                else
                {
                    m_game.SendInput(Keys.Up, true, true);
                    m_game.SendInput(Keys.Down, true, true);
                }

                return;
            }

            Vector2d mousePos = new Vector2d((int)e.X / Constants.SPRITE_SIZE, (int)e.Y / Constants.SPRITE_SIZE);

            if (mousePos.x >= 0 && mousePos.y >= 0 && mousePos.x <= Constants.FIELD_WIDTH && mousePos.y <= Constants.FIELD_HEIGHT)
            {
                if (e.Button == MouseButtons.Left)
                    m_game.DebugDrawMap(mousePos, false);
                else if (e.Button == MouseButtons.Right)
                    m_game.DebugDrawMap(mousePos, true);
            }
        }

        public void SendCommand(string cmd)
        {
            if (cmd == null)
                return;

            Console.WriteLine("Executing command: \"" + cmd + "\"");

            StringBuilder doCommand = new StringBuilder();

            int n = 0;

            // Parse command
            for (int i = 0; i < cmd.Length; i++)
                if (cmd[i] != ' ')
                {
                    doCommand.Append(cmd[i]);
                    continue;
                }
                else
                {
                    n = i + 1;
                    break;
                }

            switch (doCommand.ToString())
            {
                case "build":
                    Console.WriteLine("Build: '" + cmd[n] + "'");
                    if (n >= cmd.Length)
                        break;

                    TileList tile = (TileList)int.Parse(cmd[n].ToString());

                    if (tile <= TileList.TILE_NONE || tile >= TileList.MAX_TILES)
                        break;

                    m_game.SetCurrentBuild(tile);
                    break;

                case "quit":
                    m_game.QuitGame();
                    break;

                case "quit_save":
                    m_game.QuitGame(true);
                    break;

                case "restart":
                    m_game.Restart();
                    m_pausePanel.SetVisible(false);
                    m_endLabel.SetVisible(false);
                    m_buttonRestart.SetVisible(false);
                    m_buttonQuit.SetVisible(false);
                    break;

                default:
                    break;
            }
        }

        private void CreatePausemenu()
        {
            /*
            * Create the main panel in which UI is stored
            */
            Vector2d vecSpriteSize = new Vector2d(Constants.SPRITE_SIZE, Constants.SPRITE_SIZE);    //Reusable

            Vector2d posMainPanel = new Vector2d(0, 0);
            Vector2d sizeMainPanel = new Vector2d((Constants.FIELD_WIDTH + 1) * Constants.SPRITE_SIZE,
                (Constants.FIELD_HEIGHT + 1) * Constants.SPRITE_SIZE);

            m_pausePanel = new SnkPanel(m_game, new Dimensions2d(posMainPanel, sizeMainPanel));
            m_pausePanel.SetBGColour(Color.FromArgb(30, 0, 0, 128));
            m_pausePanel.SetVisible(false);
            m_children.AddLast(m_pausePanel);

            Vector2d posQuitButton = posMainPanel + vecSpriteSize;
            posQuitButton.y += vecSpriteSize.y * 5;
            Vector2d sizeQuitButton = new Vector2d(sizeMainPanel.x - (2 * Constants.SPRITE_SIZE), vecSpriteSize.y * 3);

            m_buttonQuit = new SnkButton(m_game, new Dimensions2d(posQuitButton, sizeQuitButton));
            m_children.AddLast(m_buttonQuit);

            m_buttonQuit.SetVisible(false);
            m_buttonQuit.SetText("\n                                           SUGRĮŽTI Į PAGRINDINĮ MENIU");
            m_buttonQuit.SetCommand("quit");

            if (m_game.IsDebug())
            {

                Vector2d posQuitAndSaveButton = new Vector2d(posQuitButton);
                posQuitAndSaveButton.y += vecSpriteSize.y * 4;

                m_dbgButtonQuitAndSave = new SnkButton(m_game, new Dimensions2d(posQuitAndSaveButton, sizeQuitButton));
                m_children.AddLast(m_dbgButtonQuitAndSave);

                m_dbgButtonQuitAndSave.SetVisible(false);
                m_dbgButtonQuitAndSave.SetText("\n                                                      IŠEITI IR IŠSAUGOTI");
                m_dbgButtonQuitAndSave.SetCommand("quit_save");
            }
        }

        public void ShowMenu(bool visible, bool debug_visible = false)
        {
            if (m_pausePanel == null)
                return;

            m_pausePanel.SetVisible(visible);

            if (m_buttonQuit != null)
                m_buttonQuit.SetVisible(visible);

            if (m_dbgButtonQuitAndSave != null)
                m_dbgButtonQuitAndSave.SetVisible(visible);
        }

        public void CreateEndMenu()
        {
            /*
            * Create the main panel in which UI is stored
            */
            Vector2d vecSpriteSize = new Vector2d(Constants.SPRITE_SIZE, Constants.SPRITE_SIZE);    //Reusable

            Vector2d posMainPanel = new Vector2d(0, 0);
            Vector2d sizeMainPanel = new Vector2d((Constants.FIELD_WIDTH + 1) * Constants.SPRITE_SIZE,
                (Constants.FIELD_HEIGHT + 1) * Constants.SPRITE_SIZE);

            Vector2d posEndLabel = posMainPanel + vecSpriteSize;
            posEndLabel.y += vecSpriteSize.y;
            Vector2d sizeEndLabel = new Vector2d(sizeMainPanel.x - (2 * Constants.SPRITE_SIZE), vecSpriteSize.y * 3);

            m_endLabel = new SnkLabel(m_game, new Dimensions2d(posEndLabel, sizeEndLabel), "label");
            m_children.AddLast(m_endLabel);

            m_endLabel.SetVisible(false);

            Vector2d posRestartButton = new Vector2d(posEndLabel);
            posRestartButton.y += vecSpriteSize.y * 8;

            m_buttonRestart = new SnkButton(m_game, new Dimensions2d(posRestartButton, sizeEndLabel));
            m_buttonRestart.SetText("\n                                                     PRADĖTI IŠ NAUJO");
            m_buttonRestart.SetCommand("restart");
            m_children.AddLast(m_buttonRestart);

            m_buttonRestart.SetVisible(false);
        }

        public void ShowEndMenu(bool victory)
        {
            if (victory)
                m_endLabel.SetText("\n                                                          JŪS LAIMĖJOTE!");
            else
                m_endLabel.SetText("\n                                                         JŪS PRALAIMĖJOTE!");

            m_pausePanel.SetVisible(true);
            m_endLabel.SetVisible(true);
            m_buttonRestart.SetVisible(true);
            m_buttonQuit.SetVisible(true);
        }
    }
}
